package com.lmc.gobang.game;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lmc.gobang.GobangApplication;
import com.lmc.gobang.mapper.UserMapper;
import com.lmc.gobang.model.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;
//这个类表示一个房间
// @Component  这里不能成为spring的组件，否则就变成单例模式 ,只能手动注入
@Slf4j
@Data
public class Room {

    private String roomId;

    private User user1;
    private User user2;

    private Integer whiteUser;

    private int MAX_ROW = 15;
    private int MAX_COL = 15;

    //表示棋盘 0-为落子  1-user1下的子  2-user2下的子
    private int[][] board = new int[MAX_ROW][MAX_COL];
//    @Autowired
    ObjectMapper objectMapper = new ObjectMapper();
//    @Autowired
    OnlineUserManager onlineUserManager;
//    @Autowired
    RoomManager roomManager;

    UserMapper userMapper;

    public Room() {
        //生成一个唯一的字符串来当作房间id
        roomId = UUID.randomUUID().toString();
        //因为Room不能是单例模式所以不能加入到spring管理
        // 所以通过手动注入 获取bean
        onlineUserManager = GobangApplication.applicationContext.getBean(OnlineUserManager.class);
        roomManager = GobangApplication.applicationContext.getBean(RoomManager.class);
        userMapper = GobangApplication.applicationContext.getBean(UserMapper.class);
    }

    //处理一次落子请求
    public void putChess(String payload) throws IOException {
        log.info("putChess");
        //1.更新服务器中棋盘的数据
        GameRequest gameRequest = objectMapper.readValue(payload, GameRequest.class);
//        GameRequest request = objectMapper.readValue(payload, GameRequest.class);
        //判断是谁下的子
        int chess = gameRequest.getUserId()==user1.getUserId()?1:2;
        int row = gameRequest.getRow();
        int col = gameRequest.getCol();
        //这里在客户端就已判断过了，但是为了代码的健壮性
        if(board[row][col]!=0){
            log.info("玩家编号: "+gameRequest.getUserId()+"请勿重复落子！");
            return;
        }
        board[row][col] = chess;
        log.info("玩家编号："+gameRequest.getUserId()+"在["+row+","+col+"]上落子");
        //打印棋盘
        printBoard();
//        if(gameRequest.getMessage().equals("putChess")){
//
//        }else{
//            log.info("收到非落子的异常响应");
//            return;
//        }
        //2.胜负判定
        int winner = isWinner(row,col,chess);
        if(winner==user1.getUserId()){
            log.info("玩家："+user1.getUsername()+"获得了胜利！");
        }else if(winner==user2.getUserId()){
            log.info("玩家："+user2.getUsername()+"获得了胜利！");
        }
        //3.给客户端返回响应
        GameResponse gameResponse = new GameResponse();
        gameResponse.setMessage("putChess");
        gameResponse.setUserId(gameRequest.getUserId());
        gameResponse.setWinner(winner);
        gameResponse.setCol(col);
        gameResponse.setRow(row);
        //获取两用户的websocketSession
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        if(session1==null){
            log.info("玩家一掉线，玩家二自动胜出");
            gameResponse.setWinner(user2.getUserId());
        }
        if(session2==null){
            log.info("玩家二掉线，玩家一自动胜出");
            gameResponse.setWinner(user1.getUserId());
        }
        if (session1!=null) {
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameResponse)));

        }
        if (session2!=null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameResponse)));
        }
        //4.游戏结束，销毁房间
        if(gameResponse.getWinner()!=0){
            int winnerId = gameResponse.getWinner();
            int loserId  = gameResponse.getWinner()==user1.getUserId()?user2.getUserId():user1.getUserId();
            log.info("玩家编号："+winnerId+"取得胜利！"+"玩家编号："+loserId+"失败！");

            onlineUserManager.exitGameRoom(user1.getUserId());
            onlineUserManager.exitGameRoom(user2.getUserId());
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
            log.info("游戏房间已销毁");

        //5.更新玩家信息
            userMapper.userWin(winnerId);
            userMapper.userLose(loserId);

        }
    }

    private void printBoard() {
        log.info("打印棋盘信息"+roomId);
        for (int i = 0; i < MAX_ROW; i++) {
            for (int j = 0; j < MAX_COL; j++) {
                System.out.print(board[i][j]+" ");
            }
            System.out.println();
        }
    }

    private int isWinner(int row, int col, int chess) {
        //判断一行
        for (int c = col-4;c<=col;c++){
            try {
                if(board[row][c]==chess &&
                board[row][c+1]==chess &&
                board[row][c+2]==chess &&
                board[row][c+3]==chess &&
                board[row][c+4]==chess){
                    //胜负已分
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                //即使越界了也没事，继续下一个循环就好了
                continue;
            }
        }

        //判断一竖
        for (int r = row-4;r<=row;r++){
            try{
                if (board[r][col]==chess &&
                        board[r+1][col]==chess &&
                        board[r+2][col]==chess &&
                        board[r+3][col]==chess &&
                        board[r+4][col]==chess){
                    //胜负已分
                    return chess==1 ? user1.getUserId():user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                //即使越界了也没事，继续下一个循环就好了
                continue;
            }
        }
        //判断左对角线
        for (int r=row-4,c=col-4;r<=row&&c<=col;r++,c++){
            try{
                if (board[r][c]==chess &&
                        board[r+1][c+1]==chess &&
                        board[r+2][c+2]==chess &&
                        board[r+3][c+3]==chess &&
                        board[r+4][c+4]==chess){
                    //胜负已分
                    return chess==1 ? user1.getUserId():user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                //即使越界了也没事，继续下一个循环就好了
                continue;
            }
        }
        //判断右对角线
        for (int r=row-4,c=col+4;r<=row&&c>=col;r++,c--){
            try{
                if (board[r][c]==chess &&
                        board[r+1][c-1]==chess &&
                        board[r+2][c-2]==chess &&
                        board[r+3][c-3]==chess &&
                        board[r+4][c-4]==chess){
                    //胜负已分
                    return chess==1?user1.getUserId():user2.getUserId();

                }
            } catch (ArrayIndexOutOfBoundsException e) {
                //即使越界了也没事，继续下一个循环就好了
                continue;
            }
        }
        return 0;
    }
}
